#pragma once

#include "imgui/imgui.h"
#include "serialise\database.h"
#include <list>

struct UiState
{
	enum class Menu
	{
		None,
		File,
		View,
		Schema,
		Records,
		FieldType,
		FieldEdit,
		Node,
		SchemaSelect,
		EnumSelect,
		SchemaEdit,
		MemberEdit,
		EnumEdit,
		EnumValueEdit
	};

	enum class Action
	{
		RequestSave,
		RenameDatabase,
		New,
		Open,
		Save,
		Exit,
		RenameField,
		RenameSchema,
		RenameNode,
		RenameMember,
		RenameEnum,
		RenameEnumValue
	};

	struct NodeData
	{
		NodeData() : expanded(false) {}
		bool expanded;
	};

	struct Node
	{
		Json::Folder* pParent;
		std::string name;
		Json::Folder* pFolder;
	};

	struct RecordPoint
	{
		RecordPoint() : jBase(0), pSchema(0) {}
		RecordPoint(Json::JBase* jBase_, const Json::Schema::Object* pSchema_, std::string name_) : jBase(jBase_), pSchema(pSchema_), name(name_) {}

		Json::JBase* jBase;
		const Json::Schema::Object* pSchema;
		std::string name;
	};

	enum class EditWindow
	{
		Schema,
		Enum,
		Record,
		Table,
	};

	UiState() : selectedMenu(Menu::None), isSaved(true), editWindow(EditWindow::Record) {}

	Imgui::Window menuWindow;
	Imgui::Window buttonWindow;
	Menu selectedMenu;
	bool isSaved;
	EditWindow editWindow;
	std::list<Action> pendingActions;
	std::string schemaView;
	std::string schemaEdit;
	std::string enumView;
	std::string enumEdit;
	std::string enumValue;
	Json::Schema::Object::FieldMap::iterator pCurrentTypeInfo;
	std::set<Node> selected;
	std::map<Node, NodeData> nodeData;
	std::list<RecordPoint> recordPointStack;
	std::string* pCurrentField;
	Json::Schema::Enum* pCurrentEnum;
	Json::JBase* pCurrentMember;
};

class Database : public App::Section
{
public:
	Database() {}
	~Database() {}

	void Initialise();
	void RunUI(Render::SurfacePtr pSurface, Imgui::Window& window);
	void OnEvent(const App::Event* pEvent) override;
	void DoMenus();
	bool Save();

	const Json::Database* GetDatabase() const {return m_pDatabase;}

private:
	bool OnInit(App::Application* pApp) override;
    void OnRender(Render::SurfacePtr pSurface) override;

	Json::Database* GetDatabase_NC() {m_uiState.isSaved = false; return m_pDatabase;}

	bool Load();
	bool DoSaveChangesDialog();
	bool DoRenameDatabase();
	void DoListWindow();
	void DoSchemaList();
	void DoEnumList();
	void DoRecordTree();
	void DoSchemaEdit();
	void DoEnumEdit();
	void DoRecordEdit();
	void DoRecordTable();
	void DoNode(Imgui::Tree& tree, const std::string& name, Json::Folder* pFolder, Json::Folder* pParent);
	void DoJObjectUI(Json::JBase* jBase, const Json::Schema::Object* pSchema);
	void DoReferenceButton(const std::string& value);
	bool DoNewElement(Json::JBase* jBase, int newElementType);

	UiState m_uiState;
	Ut::SharedPtr<Json::Database> m_pDatabase;
	Imgui::Ui m_gui;
};

inline bool operator < (const UiState::Node& a, const UiState::Node& b)
{
	if (a.pParent != b.pParent) return a.pParent < b.pParent;
	if (a.pFolder != b.pFolder) return a.pFolder < b.pFolder;
	return a.name < b.name;
}

inline bool operator == (const UiState::Node& a, const UiState::Node& b)
{
	if (a.pParent != b.pParent) return false;
	if (a.pFolder != b.pFolder) return false;
	if (a.name != b.name) return false;
	return true;
}

